﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using yiwei.Repository.Entity.core;
using yiwei.Repository.Interface;
using Z.EntityFramework.Plus;

namespace yiwei.Repository.back
{
    public class BaseRepository<T> : IRepository<T> where T : BaseEntity
    {
        private YiWeiDBContext _context;
        public BaseRepository(YiWeiDBContext context)
        {
            _context = context;
        }

        public int Add(T entity)
        {
            _context.Set<T>().Add(entity);
            return _context.SaveChanges();
        }

        public int Add(IEnumerable<T> entities)
        {
            
            _context.Set<T>().AddRange(entities);
            return _context.SaveChanges();

        }

        public async Task<int> AddAsync(T entity)
        {
            await  _context.Set<T>().AddAsync(entity);
            return await _context.SaveChangesAsync();

        }

        public async Task<int> AddAsync(IEnumerable<T> entities)
        {
            await _context.Set<T>().AddRangeAsync(entities);
            return await _context.SaveChangesAsync();
        }

        public int Delete(T entity)
        {
            this._context.Set<T>().Remove(entity);
            return _context.SaveChanges();
        }

        public int Delete(Expression<Func<T, bool>> exp)
        {
            var entities = this.Find(exp);
            return this.Delete(entities);
        }

        public int Delete(IEnumerable<T> entitys)
        {
            this._context.Set<T>().RemoveRange(entitys);
            return _context.SaveChanges();
        }

        public async  Task<int> DeleteAsync(T entity)
        {
            this._context.Set<T>().Remove(entity);
            return await _context.SaveChangesAsync();
        }

        public async Task<int> DeleteAsync(Expression<Func<T, bool>> exp)
        {
            var entities = await FindASync(exp);
            return Delete(entities);
        }

        public async Task<int> DeleteAsync(IEnumerable<T> entities)
        {
            this._context.Set<T>().RemoveRange(entities);
            return await _context.SaveChangesAsync();
        }

        public int Update(T entity)
        {
            this._context.Set<T>().Attach(entity);
            var entry = this._context.Entry(entity);
            var props = entity.GetType().GetProperties();
            foreach (var prop in props)
            {
                //非null且非PrimaryKey
                if (prop.GetValue(entity, null) != null && !entry.Property(prop.Name).Metadata.IsPrimaryKey())
                {
                    entry.Property(prop.Name).IsModified = true;
                }
            }
            return this._context.SaveChanges();
        }

        public int Update(Expression<Func<T, bool>> where, Expression<Func<T, T>> entity)
        {
            return _context.Set<T>().Where(where).Update(entity);
        }

        public async Task<int> UpdateAsync(T entity)
        {
            this._context.Set<T>().Attach(entity);
            var entry = this._context.Entry(entity);
            var props = entity.GetType().GetProperties();
            foreach (var prop in props)
            {
                //非null且非PrimaryKey
                if (prop.GetValue(entity, null) != null && !entry.Property(prop.Name).Metadata.IsPrimaryKey())
                {
                    entry.Property(prop.Name).IsModified = true;
                }
            }
            return await this._context.SaveChangesAsync();
        }

        public async Task<int> UpdateAsync(Expression<Func<T, bool>> where, Expression<Func<T, T>> entity)
        {
            return await _context.Set<T>().Where(where).UpdateAsync(entity);
        }

        public int ExecuteSql(string sql)
        {
            return _context.Database.ExecuteSqlRaw(sql);
        }

        public async Task<int> ExecuteSqlAsync(string sql)
        {
            return await this._context.Database.ExecuteSqlRawAsync(sql);
        }

        public IQueryable<T> Find(Expression<Func<T, bool>> exp = null)
        {
           return Filter(exp);
        }



        public async Task<IQueryable<T>> FindASync(Expression<Func<T, bool>> exp = null)
        {
            //return await Filter(exp);

            return null;
        }



        public T FindSingle(Expression<Func<T, bool>> exp = null)
        {
            throw new NotImplementedException();
        }

        public Task<T> FindSingleASync(Expression<Func<T, bool>> exp = null)
        {
            throw new NotImplementedException();
        }

        public int GetCount(Expression<Func<T, bool>> exp = null)
        {
            throw new NotImplementedException();
        }

        public Task<int> GetCountASync(Expression<Func<T, bool>> exp = null)
        {
            throw new NotImplementedException();
        }

        public bool IsExist(Expression<Func<T, bool>> exp)
        {
            throw new NotImplementedException();
        }

        public Task<bool> IsExistASync(Expression<Func<T, bool>> exp)
        {
            throw new NotImplementedException();
        }

        private IQueryable<T> Filter(Expression<Func<T, bool>> exp)
        {
            var dbSet = _context.Set<T>().AsNoTracking().AsQueryable();
            if (exp != null)
                dbSet = dbSet.Where(exp);
            return dbSet;
        }

        public (IEnumerable<T> list, long total) Find(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderField, int pageSize, int pageIndex, params OrderType[] orderTypes)
        {
            throw new NotImplementedException();
        }

        public Task<(IEnumerable<T> list, long total)> FindAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderField, int pageSize, int pageIndex, params OrderType[] orderTypes)
        {
            throw new NotImplementedException();
        }
    }
}
